﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Valentia.Kinection.Configuration;
using Valentia.Kinection.DataTypes;
using System.Text.RegularExpressions;

namespace Valentia.Kinection.Configuration.Manager
{
    /// <summary>
    /// User control used to add/update kinect device
    /// </summary>
    public partial class KinectDeviceControl : UserControl
    {
        #region Declarations

        /// <summary>
        /// Device ID
        /// </summary>
        private int kinectDeviceID = -1;

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor
        /// </summary>
        public KinectDeviceControl()
        {
            InitializeComponent();
            InitializeControls();           
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Set the form control values with the provided kinect device info
        /// </summary>
        /// <param name="kinectDevice">Kinect device</param>
        public void InitializeWithKinectDeviceData(KinectDevice kinectDevice)
        {            
            this.kinectDeviceID = kinectDevice.ID;

            txtDeviceName.Text = kinectDevice.KinectDeviceName;
            chkActive.Checked = kinectDevice.Active;
            chkVideoStream.Checked = kinectDevice.GenerateVideoStream;
            chkDepthStream.Checked = kinectDevice.GenerateDepthStream;
            chkSkeletonStream.Checked = kinectDevice.GenerateSkeletonStream;
            nudSkeletonSmoothing.Value = Decimal.Parse(kinectDevice.SkeletonSmoothing.ToString());
            nudSksletonCorrection.Value = Decimal.Parse(kinectDevice.SkeletonCorrection.ToString());
            nudPrediction.Value = Decimal.Parse(kinectDevice.SkeletonPrediction.ToString());
            nudJitter.Value = Decimal.Parse(kinectDevice.SkeletonJitterRadius.ToString());

            cmbVideoResoloution.Text = kinectDevice.KinectVideoResoloution.ToString();
            cmbDepthResoloution.Text = kinectDevice.KinectDepthResoloution.ToString();
            cmbSkeletonResoloution.Text = kinectDevice.KinectSkeletonResoloution.ToString();

            cmbVideoImageType.Text = kinectDevice.KinectVideoImageType.ToString();
            cmbDepthImageType.Text = kinectDevice.KinectDepthImageType.ToString();

            foreach (String ro in Enum.GetNames(typeof(KinectRuntimeOptions)))
            {
                KinectRuntimeOptions enmValue = (KinectRuntimeOptions)(Enum.Parse(typeof(KinectRuntimeOptions), ro, true));
                if ((kinectDevice.KinectRuntimeOptions & enmValue) != enmValue) continue;

                this.clbRunTimeOptions.SetItemChecked(this.clbRunTimeOptions.Items.IndexOf(ro), true);
            }

            btnSaveUpdate.Text = "   Update";
            txtDeviceName.ReadOnly = true;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Intializes form controls with defualt values
        /// </summary>
        private void InitializeControls()
        {
            String[] resolutions = Enum.GetNames(typeof(KinectImageResolution));
            

            foreach (String resolution in resolutions)
            {
                if (!resolution.Equals(KinectImageResolution.Invalid.ToString()))
                {
                    this.cmbSkeletonResoloution.Items.Add(resolution);

                    if (resolution.Contains(KinectImageResolution.Resolution640x480.ToString()) 
                        || resolution.Contains(KinectImageResolution.Resolution1280x1024.ToString()))
                    {
                        this.cmbVideoResoloution.Items.Add(resolution);
                        continue;
                    }

                    if (resolution.Contains(KinectImageResolution.Resolution80x60.ToString()) 
                        || resolution.Contains(KinectImageResolution.Resolution320x240.ToString()))
                    {
                        this.cmbDepthResoloution.Items.Add(resolution);
                    }
                }                
            }

            this.cmbVideoResoloution.SelectedIndex = 0;
            this.cmbDepthResoloution.SelectedIndex = 0;
            this.cmbSkeletonResoloution.SelectedIndex = 0;

            String[] imageTypes = Enum.GetNames(typeof(KinectImageType));

            foreach (String imageType in imageTypes)
            {
                if (imageType.StartsWith("Color"))
                {
                    this.cmbVideoImageType.Items.Add(imageType);
                    continue;
                }

                if (imageType.Equals(KinectImageType.DepthAndPlayerIndex.ToString()))
                {
                    this.cmbDepthImageType.Items.Add(imageType);
                }
            }

            this.cmbVideoImageType.SelectedIndex = 0;
            this.cmbDepthImageType.SelectedIndex = 0;

            this.clbRunTimeOptions.Items.AddRange(Enum.GetNames(typeof(KinectRuntimeOptions)));
        }
       
        /// <summary>
        /// Validates the kinect device data to be saved
        /// </summary>
        /// <returns>True/False : kinect device data is valid</returns>
        private bool IsValidData()
        {
            errProvider.Clear();
            if (txtDeviceName.Text.Trim().Equals(string.Empty))
            {
                errProvider.SetError(txtDeviceName, "Please provide device name");
                txtDeviceName.Focus();
                return false;
            }

            if (!Regex.Match(txtDeviceName.Text, "^[a-zA-Z0-9 ]+$").Success)
            {
                errProvider.SetError(txtDeviceName, "Device name must be alphanumeric");
                txtDeviceName.Focus();
                return false;
            }

            if (this.clbRunTimeOptions.CheckedItems.Count < 1)
            {
                errProvider.SetError(clbRunTimeOptions, "Please select atleast one option");
                clbRunTimeOptions.Focus();
                return false;
            }

            return true;
        }

        #endregion

        #region Form control events

        /// <summary>
        /// Occurs when Save/Update button is clicked
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Event Args</param>
        private void btnSaveUpdate_Click(object sender, EventArgs e)
        {
            if (IsValidData())
            {
                 KinectRuntimeOptions kinectRuntimeOptions = KinectRuntimeOptions.UseColor;
                    
                    int count = 0;

                    foreach (object itemChecked in clbRunTimeOptions.CheckedItems)
                    {
                        if (count == 0)
                        {
                            kinectRuntimeOptions = (KinectRuntimeOptions)(Enum.Parse(typeof(KinectRuntimeOptions), itemChecked.ToString(), true));
                            count++;
                        }
                        else
                        {
                            kinectRuntimeOptions |= (KinectRuntimeOptions)(Enum.Parse(typeof(KinectRuntimeOptions), itemChecked.ToString(), true));
                        }                    
                    }

                if (this.kinectDeviceID == -1)
                {                    
                    ConfigurationHelper.SaveKinectDevice(txtDeviceName.Text, txtDeviceName.Text, chkActive.Checked
                        , kinectRuntimeOptions, chkVideoStream.Checked, chkDepthStream.Checked, chkSkeletonStream.Checked
                        , Double.Parse(nudSkeletonSmoothing.Value.ToString()), Double.Parse(nudSksletonCorrection.Value.ToString())
                        , Double.Parse(nudPrediction.Value.ToString()), Double.Parse(nudJitter.Value.ToString())
                        , Double.Parse(nudMaxDeviation.Value.ToString()), (KinectImageResolution)Enum.Parse(typeof(KinectImageResolution)
                        , cmbVideoResoloution.SelectedItem.ToString())
                        , (KinectImageResolution)Enum.Parse(typeof(KinectImageResolution), cmbDepthResoloution.SelectedItem.ToString())
                        , (KinectImageResolution)Enum.Parse(typeof(KinectImageResolution), cmbSkeletonResoloution.SelectedItem.ToString())
                        , (KinectImageType)Enum.Parse(typeof(KinectImageType), cmbVideoImageType.SelectedItem.ToString())
                        , (KinectImageType)Enum.Parse(typeof(KinectImageType), cmbDepthImageType.SelectedItem.ToString()));                    
                }
                else
                {
                    using (ConfigDatabaseEntities context = ConfigurationHelper.GetContext())
                    {
                        KinectDevice kinectDevice = ConfigurationHelper.GetKinectDeviceByName(context, txtDeviceName.Text);

                        if (kinectDevice != null)
                        {
                            kinectDevice.Active = chkActive.Checked;
                            kinectDevice.KinectRuntimeOptions = kinectRuntimeOptions;

                            kinectDevice.GenerateVideoStream = chkVideoStream.Checked;
                            kinectDevice.GenerateDepthStream = chkDepthStream.Checked;
                            kinectDevice.GenerateSkeletonStream = chkSkeletonStream.Checked;
                            kinectDevice.SkeletonSmoothing = Double.Parse(nudSkeletonSmoothing.Value.ToString());
                            kinectDevice.SkeletonCorrection = Double.Parse(nudSksletonCorrection.Value.ToString());
                            kinectDevice.SkeletonPrediction = Double.Parse(nudPrediction.Value.ToString());
                            kinectDevice.SkeletonJitterRadius = Double.Parse(nudJitter.Value.ToString());
                            kinectDevice.SkeletonMaxDeviationRadius = Double.Parse(nudMaxDeviation.Value.ToString());

                            kinectDevice.KinectVideoResoloution = (KinectImageResolution)Enum.Parse(typeof(KinectImageResolution)
                                , cmbVideoResoloution.SelectedItem.ToString());
                            kinectDevice.KinectDepthResoloution = (KinectImageResolution)Enum.Parse(typeof(KinectImageResolution)
                                , cmbDepthResoloution.SelectedItem.ToString());
                            kinectDevice.KinectSkeletonResoloution = (KinectImageResolution)Enum.Parse(typeof(KinectImageResolution)
                                , cmbSkeletonResoloution.SelectedItem.ToString());
                            kinectDevice.KinectVideoImageType = (KinectImageType)Enum.Parse(typeof(KinectImageType)
                                , cmbVideoImageType.SelectedItem.ToString());
                            kinectDevice.KinectDepthImageType = (KinectImageType)Enum.Parse(typeof(KinectImageType)
                                , cmbDepthImageType.SelectedItem.ToString());

                            context.SaveChanges();
                        }
                    }                    
                }
                ((Form)(this.Parent)).Close();
            }         
        }

        /// <summary>
        /// Occurs when Cancel button is clicked
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Event Args</param>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            ((Form)(this.Parent)).Close();
        }

        /// <summary>
        /// Occurs when select all check box checked status change
        /// </summary>
        /// <param name="sender">Sender</param>
        /// <param name="e">Event Args</param>
        private void chkSelectAll_CheckedChanged(object sender, EventArgs e)
        {
            if (chkSelectAll.Checked)
            {
                for (int i = 0; i < clbRunTimeOptions.Items.Count; i++)
                {
                    clbRunTimeOptions.SetItemChecked(i, true);
                }
            }
            else
            {
                for (int i = 0; i < clbRunTimeOptions.Items.Count; i++)
                {
                    clbRunTimeOptions.SetItemChecked(i, false);
                }
            }
        }

        #endregion
    }
}

